﻿/*******************************************************************************
  ChangeLog:
  06-07-2013 : Scott : Upgraded XMLFormLocation to set formPath to null when locations do not exist.
                       Added DropDownStyle and DataSource to ComboBox.
                       Added "datatype" to Extended Tag, to store strings for data type. You can use this for Phone Number and
                           Zip Code validation for example, or whatever else you may need.
                       copyFormToClipboard changed to BOOL return type. Allows verification of data during copy without the need
                           for external checks in your code.
  03-07-2013 : Scott : Upgraded XMLFormLocation to nonstatic object to store FormPath and FormList.
                       Bugfix in Loading templates with SATextBox where PasswordChar would cause an exception.
  02-25-2013 : Scott : Added WordWrap property for Serialize/Deserialize with TextBox and SATextBox controls.
                       Updated projects and LoadXMLTemplate to work with iDesignSurgace flag, to centralize the functions.
                       Added PasswordChar property for Serialize/Deserialize with TextBox and SATextBox controls.
                       Added HideSelection property for Serialize/Deserialize with TextBox and SATextBox controls.
                       Added MaxLength property for Serialize/Deserialize with TextBox and SATextBox controls.
                       Added MaximumSize and MinimumSize  for Serialize/Deserialize with all controls.
 

 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml.Serialization;
using pF.DesignSurfaceExt;
using SATBox;

namespace XMLFT
{
    #region XML Form Class

    /// <summary>
    /// XMLFormTemplate Class Object
    /// This is used for serializing objects/form controls to XML file for storage and retrieval.
    /// When read back in, we can switch case the object type name property to recreate the controls for the forms.
    /// </summary>
    [Serializable]
    [XmlRoot("XMLFormTemplate")]
    public class XMLFormTemplate
    {
        public List<XMLFormControl> FormControls;

        /// <summary>
        /// Public Default Constructor
        /// </summary>
        public XMLFormTemplate()
        {
            FormControls = new List<XMLFormControl>();
        }

        /// <summary>
        /// Returns the Count for FormControls currently stored in the XMLFormTemplate Object.
        /// </summary>
        /// <returns></returns>
        public int Count()
        {
            return this.FormControls.Count;
        }

        /// <summary>
        /// Add a single control to the List of FormControls Object.
        /// </summary>
        /// <param name="child">Control to add</param>
        /// <returns>true if able to add the control</returns>
        public bool AddSingle(Control child)
        {
            XMLFormControl newFormControl = new XMLFormControl();

            newFormControl.type = child.GetType().ToString();
            if (child.Name.IndexOf("eFControl") == -1)
            {
                newFormControl.name = "eFControl" + child.Name.ToString();
            }
            else
            {
                newFormControl.name = child.Name.ToString();
            }
            newFormControl.text = child.Text.Length > 0 ? child.Text.ToString() : "";
            newFormControl.tag = child.Tag != null ? child.Tag : "";
            newFormControl.visible = child.Visible.ToString();

            PointConverter pc = new PointConverter();
            SizeConverter sc = new SizeConverter();
            newFormControl.location = pc.ConvertToString(child.Location);
            newFormControl.size = sc.ConvertToString(child.Size);
            newFormControl.minsize = sc.ConvertToString(child.MinimumSize);
            newFormControl.maxsize = sc.ConvertToString(child.MaximumSize);

            newFormControl.tabindex = child.TabIndex.ToString();

            if (child.GetType() == typeof(TextBox) || child.GetType() == typeof(SATextBox))
            {
                newFormControl.multiline = ((TextBox)child).Multiline.ToString();
                newFormControl.roControl = ((TextBox)child).ReadOnly.ToString();
                newFormControl.wordwrap = ((TextBox)child).WordWrap.ToString();
                newFormControl.hideselection = ((TextBox)child).HideSelection.ToString();
                newFormControl.maxlength = ((TextBox)child).MaxLength.ToString();
                if (((TextBox)child).PasswordChar != Char.Parse("\0"))
                {
                    newFormControl.passwordchar = ((TextBox)child).PasswordChar.ToString();
                }
            }
            else if (child.GetType() == typeof(ComboBox))
            {
                foreach (string item in ((ComboBox)child).Items)
                {
                    if (item == null)
                        continue;
                    newFormControl.display.Add(item.ToString());
                }
            }
            else if (child.GetType() == typeof(Label))
            {
                FontConverter thisCon = new FontConverter();
                string thisFont = thisCon.ConvertToString(child.Font);
                newFormControl.fontString = thisFont;
                newFormControl.textAlign = ((Label)child).TextAlign.ToString();
            }

            this.FormControls.Add(newFormControl);
            return true;
        }

        /// <summary>
        /// Adds all child controls of passed root control (panel, group box, etc) to the XMLFormTemplate Object.
        /// </summary>
        /// <param name="GroupControl">Parent Container of the Controls you wish to export.</param>
        /// <returns>true on success</returns>
        public bool AddAll(Control GroupControl)
        {
            foreach (Control child in GroupControl.Controls)
            {
                XMLFormControl newFormControl = new XMLFormControl();

                newFormControl.type = child.GetType().ToString();
                if (child.Name.IndexOf("eFControl") == -1)
                {
                    newFormControl.name = "eFControl" + child.Name.ToString();
                }
                else
                {
                    newFormControl.name = child.Name.ToString();
                }
                newFormControl.text = child.Text.Length > 0 ? child.Text.ToString() : "";
                newFormControl.tag = child.Tag != null ? child.Tag : "";
                newFormControl.visible = child.Visible.ToString();

                PointConverter pc = new PointConverter();
                SizeConverter sc = new SizeConverter();
                newFormControl.location = pc.ConvertToString(child.Location);
                newFormControl.size = sc.ConvertToString(child.Size);
                newFormControl.minsize = sc.ConvertToString(child.MinimumSize);
                newFormControl.maxsize = sc.ConvertToString(child.MaximumSize);

                newFormControl.tabindex = child.TabIndex.ToString();

                if (child.GetType() == typeof(TextBox) || child.GetType() == typeof(SATextBox))
                {
                    newFormControl.multiline = ((TextBox)child).Multiline.ToString();
                    newFormControl.roControl = ((TextBox)child).ReadOnly.ToString();
                    newFormControl.wordwrap = ((TextBox)child).WordWrap.ToString();
                    newFormControl.hideselection = ((TextBox)child).HideSelection.ToString();
                    newFormControl.maxlength = ((TextBox)child).MaxLength.ToString();
                    if (((TextBox)child).PasswordChar != Char.Parse("\0"))
                    {
                        newFormControl.passwordchar = ((TextBox)child).PasswordChar.ToString();
                    }
                }
                else if (child.GetType() == typeof(ComboBox))
                {
                    foreach (string item in ((ComboBox)child).Items)
                    {
                        if (item == null)
                            continue;
                        newFormControl.display.Add(item.ToString());
                    }
                }
                else if (child.GetType() == typeof(Label))
                {
                    FontConverter thisCon = new FontConverter();
                    string thisFont = thisCon.ConvertToString(child.Font);
                    newFormControl.fontString = thisFont;
                    newFormControl.textAlign = ((Label)child).TextAlign.ToString();
                }

                this.FormControls.Add(newFormControl);
            }
            return true;
        }

        /// <summary>
        /// Convert a string to Bool
        /// </summary>
        /// <param name="value">String to convert. Such as "", "0", and "false".</param>
        /// <returns>null, String.Empty, "", "0", and "false" returns False, anything else is True.</returns>
        private bool ToBoolean(string value)
        {
            if (value == null) return false; // Who would send a null reference to this function? haha.. =D

            value = value.ToLower();
            // FIXME : Should probably change this to a switch/case.
            if (value == "" || value == "0" || value == "false" || value == string.Empty || value == String.Empty || value == "no")
                return false;
            else
                return true;
        }

        /// <summary>
        /// Initial function to load the XML Template File back to a list of Controls with settings and Extended Tag intact.
        /// </summary>
        /// <param name="templateFile">XML Template File</param>
        /// <param name="toControl">The control you want to add the template to. A windows Form, Panel, etc.</param>
        /// <param name="isurf">Default is null, passed by Designer System.</param>
        /// <returns>true/false based on success of loading into toControl.</returns>
        public bool LoadXMLTemplate(string templateFile, Control toControl, IDesignSurfaceExt isurf = null)
        {
            string templateLoc = templateFile;
            XMLFormTemplate template = null;

            if (!File.Exists(templateLoc))
            {
                XMLFTException e = new XMLFTException("Cannot find template file: " + templateLoc);
                e.TemplateFile = templateLoc;
                throw e;
            }
            
            XmlSerializer xs = new XmlSerializer(typeof(XMLFormTemplate));
            TextReader reader = new StreamReader(templateLoc);

            template = (XMLFormTemplate)xs.Deserialize(reader);
            reader.Close();
            xs = null;
            if (template == null)
            {
                XMLFTException e = new XMLFTException("Could not deserialize the template file: " + templateLoc);
                e.TemplateFile = templateLoc;
                throw e;
            }

            foreach (XMLFormControl formControl in template.FormControls)
            {
                Control newControl = null;
                PointConverter pc = null; pc = new PointConverter();
                SizeConverter sc = null; sc = new SizeConverter();
                Size thisSize = (Size)sc.ConvertFromString(formControl.size);
                Point thisPoint = (Point)pc.ConvertFromString(formControl.location);
                
                switch (formControl.type)
                {
                    case "System.Windows.Forms.CheckBox":
                        if (isurf != null)
                        {
                            newControl = (CheckBox)isurf.CreateControl(typeof(CheckBox), thisSize, thisPoint);
                        }
                        else
                        {
                            newControl = new CheckBox();
                        }
                        ((CheckBox)newControl).Checked = Convert.ToBoolean(formControl.cDefault);
                        break;
                    case "System.Windows.Forms.TextBox":
                        if (isurf != null)
                        {
                            newControl = (TextBox)isurf.CreateControl(typeof(TextBox), thisSize, thisPoint);
                        }
                        else
                        {
                            newControl = new TextBox();
                        }
                        ((TextBox)newControl).Text = formControl.cDefault;
                        ((TextBox)newControl).Multiline = Convert.ToBoolean(formControl.multiline);
                        ((TextBox)newControl).ReadOnly = Convert.ToBoolean(formControl.roControl);
                        ((TextBox)newControl).WordWrap = Convert.ToBoolean(formControl.roControl);
                        ((TextBox)newControl).HideSelection = Convert.ToBoolean(formControl.hideselection);
                        ((TextBox)newControl).MaxLength = Convert.ToInt32(formControl.maxlength);
                        if (formControl.passwordchar == String.Empty || formControl.passwordchar == null)
                        {
                            ((TextBox)newControl).PasswordChar = Char.Parse("\0");
                        } else {
                            ((TextBox)newControl).PasswordChar = Convert.ToChar(formControl.passwordchar);
                        }
                        // FIXME : Look at control properties, so we can look at native support rather than forced.
                        if (((TextBox)newControl).Multiline)
                        {
                            ((TextBox)newControl).ScrollBars = ScrollBars.Vertical;
                        }
                        break;
                    case "SATBox.SATextBox":
                        if (isurf != null)
                        {
                            newControl = (SATextBox)isurf.CreateControl(typeof(SATextBox), thisSize, thisPoint);
                        }
                        else
                        {
                            newControl = new SATextBox();
                        }
                        ((SATextBox)newControl).Text = formControl.cDefault;
                        ((SATextBox)newControl).Multiline = Convert.ToBoolean(formControl.multiline);
                        ((SATextBox)newControl).ReadOnly = Convert.ToBoolean(formControl.roControl);
                        ((SATextBox)newControl).WordWrap = Convert.ToBoolean(formControl.roControl);
                        ((SATextBox)newControl).HideSelection = Convert.ToBoolean(formControl.hideselection);
                        ((SATextBox)newControl).MaxLength = Convert.ToInt32(formControl.maxlength);
                        if (formControl.passwordchar == String.Empty || formControl.passwordchar == null)
                        {
                            ((TextBox)newControl).PasswordChar = Char.Parse("\0");
                        }
                        else
                        {
                            ((TextBox)newControl).PasswordChar = Convert.ToChar(formControl.passwordchar);
                        }
                        // FIXME : Look at control properties, so we can look at native support rather than forced.
                        if (((SATextBox)newControl).Multiline)
                        {
                            ((SATextBox)newControl).ScrollBars = ScrollBars.Vertical;
                        }
                        break;
                    case "System.Windows.Forms.Label":
                        if (isurf != null)
                        {
                            newControl = (Label)isurf.CreateControl(typeof(Label), thisSize, thisPoint);
                        }
                        else
                        {
                            newControl = new Label();
                        }
                        if (formControl.fontString != null)
                        {
                            FontConverter thisCon = new FontConverter();
                            Font thisFont = (Font)thisCon.ConvertFromString(formControl.fontString);
                            newControl.Font = thisFont;
                        }
                        if (formControl.textAlign != null)
                        {
                            ContentAlignment thisAlign = ContentAlignment.MiddleCenter;
                            switch (formControl.textAlign)
                            {
                                case "BottomCenter": thisAlign = ContentAlignment.BottomCenter;
                                    break;
                                case "BottomLeft": thisAlign = ContentAlignment.BottomLeft;
                                    break;
                                case "BottomRight": thisAlign = ContentAlignment.BottomRight;
                                    break;
                                case "MiddleCenter": thisAlign = ContentAlignment.MiddleCenter;
                                    break;
                                case "MiddleLeft": thisAlign = ContentAlignment.MiddleLeft;
                                    break;
                                case "MiddleRight": thisAlign = ContentAlignment.MiddleRight;
                                    break;
                                case "TopCenter": thisAlign = ContentAlignment.TopCenter;
                                    break;
                                case "TopLeft": thisAlign = ContentAlignment.TopLeft;
                                    break;
                                case "TopRight": thisAlign = ContentAlignment.TopRight;
                                    break;
                            }

                            ((Label)newControl).TextAlign = thisAlign;
                        }
                        break;
                    case "System.Windows.Forms.ComboBox":
                        if (isurf != null)
                        {
                            newControl = (ComboBox)isurf.CreateControl(typeof(ComboBox), thisSize, thisPoint);
                            foreach (string thisItem in formControl.display)
                            {
                                ((ComboBox)newControl).Items.Add(thisItem);
                            }
                        }
                        else
                        {
                            newControl = new ComboBox();
                            ((ComboBox)newControl).DataSource = formControl.display;
                        }
                        ((ComboBox)newControl).DropDownStyle = ComboBoxStyle.DropDownList;
                        break;
                }

                newControl.Text = formControl.text;
                newControl.Name = formControl.name;
                newControl.Tag = formControl.tag;
                newControl.Visible = Convert.ToBoolean(formControl.visible);
                newControl.Location = (Point)pc.ConvertFromString(formControl.location);
                newControl.Size = (Size)sc.ConvertFromString(formControl.size);
                newControl.MinimumSize = (Size)sc.ConvertFromString(formControl.minsize);
                newControl.MaximumSize = (Size)sc.ConvertFromString(formControl.maxsize);
                newControl.TabIndex = Convert.ToInt16(formControl.tabindex);

                if (newControl.GetType() == typeof(ComboBox))
                {
                    ((ComboBox)newControl).DataSource = formControl.display;
                    ((ComboBox)newControl).DropDownStyle = ComboBoxStyle.DropDownList;
                }

                newControl.Parent = toControl;
                if (!toControl.Controls.Contains(newControl))
                    toControl.Controls.Add(newControl);
                if (isurf == null)
                { 
                    newControl.Tag = new XMLFormExtendedTag(newControl.Tag.ToString());
                    // Position Extended Member will override the TabIndex, so that they can tab through in the same order the template wants.
                    if (((XMLFormExtendedTag)newControl.Tag).position > 0)
                        newControl.TabIndex = Convert.ToInt16(((XMLFormExtendedTag)newControl.Tag).position);
                }
            }

            return true;
        }

        /// <summary>
        /// Saves the Template to XML.
        /// </summary>
        /// <returns>true/false based on success of saving the file.</returns>
        public bool SaveXMLTemplate()
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.AddExtension = true;
            dialog.FileName = "New_Form";
            dialog.Filter = "XML files (*.xml)|*.xml";

            if (dialog.ShowDialog() != DialogResult.OK)
            {
                XMLFTException e = new XMLFTException("Error Saving New Form or No Filename Given!");
                e.TemplateFile = "";
                throw e;
            }
            dialog.Dispose();

            try
            {
                TextWriter textwriter = new StreamWriter(dialog.FileName);
                XmlSerializer xs = new XmlSerializer(this.GetType());
                xs.Serialize(textwriter, this);
                textwriter.Close();
            }
            catch (Exception ex)
            {
                XMLFTException e = new XMLFTException(ex.Message);
                e.TemplateFile = "";
                throw e;
            }

            return true;
        }

    }

    /// <summary>
    /// This is the secondary object for forms. This controls the individual form controls themselves.
    /// Members of the Controls that can be saved, will be found here.
    /// </summary>
    [Serializable]
    public class XMLFormControl
    {
        // Base object string stuff
        public string type;
        public string name;
        public string text;
        public object tag;
        public string roControl; // Read Only Control
        public string visible;
        public string cDefault;
        public string fontString;
        public string textAlign;

        public string passwordchar;
        public string hideselection;
        public string maxlength;

        // Used for combo boxes, etc where a Collection might exist.
        public List<string> display = new List<string>();

        public string location, size, minsize, maxsize;
        public string multiline, tabindex;
        public string wordwrap;

        public XMLFormControl()
        {
        }
    }


    /// <summary>
    /// This is a Dictionary to hold Extended Tag information. Such as Required, Requires <control name> and so forth.
    /// </summary>
    [Serializable]
    public class XMLFormExtendedTag
    {
        public string text = null;
        public bool required = false;
        public string requires = null;
        public int position = 0;
        public bool noprint = false;

        // Email Related
        public bool to = false;
        public bool cc = false;
        public bool subject = false;

        // Used for the Outlook Templates where you replace this id, with the control's text/setting.
        public string outlookID;
        // Used for stuff like Phone Number, Zip Code, etc.
        public string dataType; 

        /// <summary>
        /// Default Constructor
        /// </summary>
        public XMLFormExtendedTag()
        {
        }

        /// <summary>
        /// Default Constructor
        /// </summary>
        public XMLFormExtendedTag(String stringTag)
        {
            BuildTag(stringTag);
        }

        /// <summary>
        /// Builds the Extended Tag object from a passed formatted string.
        /// </summary>
        /// <param name="oldTag">Extended Tag information in formatted string.</param>
        public void BuildTag(string oldTag)
        {
            string[] splitTag = oldTag.Split(',');
            for (int i = 0; i < splitTag.Length; i++)
            {
                string[] tagEntry = splitTag[i].Split(':');
                switch (tagEntry[0].ToLower())
                {
                    case "text": this.text = tagEntry[1].ToString(); break;
                    case "required": this.required = this.ToBoolean(tagEntry[1].ToString()); break;
                    case "noprint": this.noprint = this.ToBoolean(tagEntry[1].ToString()); break;
                    case "requires": this.requires = tagEntry[1].ToString(); break;
                    case "position": this.position = Convert.ToInt16(tagEntry[1].ToString()); break;
                    case "to": this.to = this.ToBoolean(tagEntry[1].ToString()); break;
                    case "cc": this.cc = this.ToBoolean(tagEntry[1].ToString()); break;
                    case "subject": this.subject = this.ToBoolean(tagEntry[1].ToString()); break;
                    case "datatype": this.dataType = tagEntry[1].ToString(); break;
                    case "outlookid": this.outlookID = tagEntry[1].ToString(); break;
                }
            }
        }

        /// <summary>
        /// Builds the String to store to file for the Extended Tag object.
        /// </summary>
        /// <returns>string</returns>
        public string BuildString()
        {
            StringBuilder thisString = new StringBuilder();
            if (text != null)
                thisString.Append("text:" + text + ",");
            if (requires != null)
                thisString.Append("requires:" + requires + ",");
            if (dataType != null)
                thisString.Append("datatype:" + dataType + ",");
            if (outlookID != null)
                thisString.Append("outlookid:" + outlookID + ",");
            thisString.Append("required:" + (required ? 1 : 0) + ",");
            thisString.Append("position:" + position.ToString() + ",");
            thisString.Append("noprint:" + (noprint ? 1 : 0) + ",");
            thisString.Append("to:" + (to ? 1 : 0) + ",");
            thisString.Append("cc:" + (cc ? 1 : 0) + ",");
            thisString.Append("subject:" + (subject ? 1 : 0) + ",");

            return thisString.ToString();
        }

        /// <summary>
        /// Convert a string to Bool
        /// </summary>
        /// <param name="value">String to convert. Such as "", "0", and "false".</param>
        /// <returns>null, String.Empty, "", "0", and "false" returns False, anything else is True.</returns>
        private bool ToBoolean(string value)
        {
            if (value == null) return false; // Who would send a null reference to this function? haha.. =D

            value = value.ToLower();
            // FIXME : Should probably change this to a switch/case.
            if (value == "" || value == "0" || value == "false" || value == string.Empty || value == String.Empty || value == "no")
                return false;
            else
                return true;
        }

    }

    #endregion

    #region Class for storing all the form paths, etc. Master form options.

    /// <summary>
    /// Storage object for default form locations.
    /// FormList.xml is the file that contains the list of templates so you can use drowdowns to select forms on the fly.
    /// </summary>
    public class XMLFormLocation
    {

        private string formPath;
        private string formList;

        /// <summary>
        /// Default Constructor.
        /// Sets to Application.StartupPath+\Forms\ for forms.
        /// Sets to FormList.xml for form list file.
        /// If formPath is not a valid Directory, it sets it to null.
        /// </summary>
        public XMLFormLocation()
        {
            formPath = Application.StartupPath + @"\Forms\";
            if (!Directory.Exists(formPath))
            {
                formPath = null;
            }
            formList = "FormList.xml";
        }

        /// <summary>
        /// Constructor allowing you to specify path, still uses FormList.xml for list file.
        /// If formPath is not a valid Directory, it sets it to null.
        /// </summary>
        /// <param name="FormPath"></param>
        public XMLFormLocation(string FormPath)
        {
            formPath = FormPath;
            if (!Directory.Exists(formPath))
            {
                formPath = null;
            }
            formList = "FormList.xml";
        }

        /// <summary>
        /// Constructor allowing you to set form path and form list filename.
        /// If formPath is not a valid Directory, it sets it to null.
        /// </summary>
        /// <param name="FormPath"></param>
        /// <param name="FormList"></param>
        public XMLFormLocation(string FormPath, string FormList)
        {
            formPath = FormPath;
            if (!Directory.Exists(formPath))
            {
                formPath = null;
            }
            formList = FormList;
        }

        /// <summary>
        /// Returns the path and filename of the Forms List file.
        /// Set allows you to change the name of the Forms List file.
        /// </summary>
        public string FormsList
        {
            get { return formPath + formList; }
            set { formList = value; }
        }

        /// <summary>
        /// Returns the path only of where the Email Forms are located.
        /// Set allows you to change the path to the Forms List file.
        /// If formPath is not a valid Directory, it sets it to null.
        /// </summary>
        public string FormsPath
        {
            get { return formPath; }
            set
            {
                if (!Directory.Exists(formPath))
                {
                    formPath = null;
                }
                else
                    formPath = value;
            }
        }

    }

    #endregion

    #region Form Helper class for working with Windows Forms that make use of XML Form.

    /// <summary>
    /// Form Helper class for working with Windows Forms that make use of XML Form to make the transitions smoother.
    /// </summary>
    public class XMLFormHelper
    {

        /// <summary>
        /// Resets all controls back to their defaults. Defaults for Textbox is blank, checkboxes is unchecked, comboboxes is Index 0.
        /// </summary>
        /// <param name="workingBox">The root control the form was loaded to. Such as GroupBox, Panel, Windows.Form, etc.</param>
        public static void resetFormContainer(Control workingBox)
        {

            foreach (Control child in workingBox.Controls)
            {
                if (child is SATextBox)
                {
                    SATextBox thisBox = (SATextBox)child;
                    thisBox.Text = "";
                }
                else if (child is TextBox)
                {
                    TextBox thisBox = (TextBox)child;
                    thisBox.Text = "";
                }
                else if (child is ComboBox)
                {
                    ComboBox thisCombo = (ComboBox)child;
                    thisCombo.SelectedIndex = 0;
                }
                else if (child is CheckBox)
                {
                    CheckBox thisCheckBox = (CheckBox)child;
                    thisCheckBox.Checked = false;
                }
            }
        }

        /// <summary>
        /// Copies the template to the clipboard in the format provided by the Extended Tag.
        /// </summary>
        /// <param name="workingBox">The root control the form was loaded to. Such as GroupBox, Panel, Windows.Form, etc.</param>
        public static bool copyFormToClipboard(Control workingBox)
        {
            try
            {
                Clipboard.Clear();
            }
            catch { }

            StringBuilder templateResults = new StringBuilder();
            Dictionary<int, string> templateLines = new Dictionary<int, string>();

            foreach (Control child in workingBox.Controls)
            {
                if (child.Tag == null)
                    continue;

                XMLFormExtendedTag thisTag = (XMLFormExtendedTag)child.Tag;

                if (thisTag.noprint)
                    continue;

                switch (child.GetType().ToString())
                {
                    case "System.Windows.Forms.TextBox": if (thisTag.required && child.Text.Length == 0)
                        {
                            MessageBox.Show("A required field was not filled out: " + thisTag.text, "Missing Information?", MessageBoxButtons.OK);
                            return false;
                        }
                        templateLines.Add(thisTag.position, thisTag.text + ": " + child.Text);
                        if (thisTag.dataType == "Phone Number")
                        {
                            if (!Regex.IsMatch(child.Text, @"^(1?(-?\d{3})-?)?(\d{3})(-?\d{4})$") || child.Text.Contains("000-") || child.Text.Contains("0000000000"))
                            {
                                MessageBox.Show("The phone number entered is not valid: " + thisTag.text, "Invalid Phone Number", MessageBoxButtons.OK);
                                return false;
                            }
                        }
                         break;
                    case "SATBox.SATextBox": if (thisTag.required && child.Text.Length == 0)
                        {
                            MessageBox.Show("A required field was not filled out: " + thisTag.text, "Missing Information?", MessageBoxButtons.OK);
                            return false;
                        }
                        if (thisTag.dataType == "Phone Number")
                        {
                            if (!Regex.IsMatch(child.Text, @"^(1?(-?\d{3})-?)?(\d{3})(-?\d{4})$") || child.Text.Contains("000-") || child.Text.Contains("0000000000"))
                            {
                                MessageBox.Show("The phone number entered is not valid: " + thisTag.text, "Invalid Phone Number", MessageBoxButtons.OK);
                                return false;
                            }
                        }
                        templateLines.Add(thisTag.position, thisTag.text + ": " + child.Text);
                        break;
                    case "System.Windows.Forms.ComboBox": if ((((ComboBox)child).SelectedIndex == 0) && thisTag.required)
                        {
                            MessageBox.Show("A required field was not filled out: " + thisTag.text, "Missing Information?", MessageBoxButtons.OK);
                            return false;
                        }
                        templateLines.Add(thisTag.position, (thisTag.text + ": " + ((ComboBox)child).SelectedItem));
                        break;
                    case "System.Windows.Forms.CheckBox": if (thisTag.required && ((CheckBox)child).Checked == false)
                        {
                            MessageBox.Show("A required field was not filled out: " + thisTag.text, "Missing Information?", MessageBoxButtons.OK);
                            return false;
                        }
                        templateLines.Add(thisTag.position, (thisTag.text + ": " + (((CheckBox)child).Checked ? "Yes" : "No")));
                        break;
                }
            }

            // This will re-order it based on the position entry from the Extended Tag. 
            var q = templateLines.OrderBy(kvp => kvp.Key);
            foreach (var lineEntry in q)
            {
                templateResults.AppendLine(lineEntry.Value);
            }

            try
            {
                Clipboard.SetText(templateResults.ToString());
            }
            catch { }
            return true;
        }

    }

    #endregion
}
